#ifndef TLRSTRUCTMODEL_H
#define TLRSTRUCTMODEL_H

#include <QString>
#include <QList>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonParseError>
#include <QDebug>
#include <QColor>

//通讯方式
enum TCommType {
    ctNet,     //网络通讯方式
    ctSerial,  //串口通讯方式
};

//数据类型单元
struct TDataTypeUnit {
    QString type;     //数据类型
    int size;         //数据长度

    /*
     * 默认构造函数
     */
    TDataTypeUnit() {
        type = "char";
        size = sizeof(char);
    }

    /*
     * 构造函数
     * ntype : 类型
     * nsize : 类型大小
     */
    TDataTypeUnit(const QString &ntype,int nsize) {
        type = ntype;
        size = nsize;
    }

    /*
     * 重载==运算符
     * ndatatypeunit : 对比
     */
    bool operator==(const TDataTypeUnit &ndatatypeunit) const{
        bool nret = false;
        if(type == ndatatypeunit.type) {
            nret = true;
        }
        return nret;
    }
};

//基本数据类型
const QList<TDataTypeUnit> PLAIN_DATA_TYPE = {
    TDataTypeUnit("char",sizeof(char)),TDataTypeUnit("u8",sizeof(quint8)),
    TDataTypeUnit("u16",sizeof(quint16)),TDataTypeUnit("s16",sizeof(qint16)),
    TDataTypeUnit("u32",sizeof(quint32)),TDataTypeUnit("s32",sizeof(qint32))
};

//结构体成员
struct TLRStructMember {
    QString name;   //成员名称
    QString desc;   //成员注释
    QString type;   //成员类型
    int count;      //成员数量(单独或数组)

    int offset;     //偏移地址
    int unitSize;   //单元尺寸

    /*
     * 是否基本数据类型
     * ndatatype : 待测试数据类型
     * 返回值     : true: 基本数据类型 false:非基本数据类型
     */
    bool isPlainDataType() const {
        bool nret = false;
        if(PLAIN_DATA_TYPE.indexOf(TDataTypeUnit(type,-1)) != -1) {
            nret = true;
        }
        return nret;
    }

    /*
     * 获取类型
     * 返回值 : 类型
     */
    QString getFullType() const {
        QString ntypestr;
        ntypestr = type;
        if(isArray()) {
            ntypestr += QString("[%1]").arg(count);
        }
        return ntypestr;
    }

    /*
     * 是否数组
     * 返回值 : true:数组 false:不是数组
     */
    bool isArray() const {
        return count>1?true:false;
    }

    /*
     * 是否字符串
     * 返回值 : true:是 false:否
     */
    bool isString() const {
        bool nret = false;
        if(isArray() && (type == "char")) {
            nret = true;
        }
        return nret;
    }

    /*
     * 获取值
     * narridx : 数组下标
     * 返回值   : 值
     */
    QString getValStr(const QByteArray &nmemdata,int nbaseoffset,int narridx = -1) const {
        QString nvalstr;
        //基本数据类型
        if(isPlainDataType()) {
            //数组类型的描述
            if((isArray() && narridx == -1)) {
                //字符串特殊处理
                if(isString()) {
                    nvalstr = QString("\"%1\"  <%2 个项>").arg(nmemdata.data()).arg(count);
                }
                else {
                    nvalstr = QString("<%1 个项>").arg(count);
                }
            }
            else {
                int noffset = getOffset(nbaseoffset,narridx);
                const char *pdata = nmemdata.data() + noffset;
                if(type == "char") {
                    char nchar = *pdata;
                    nvalstr = QString("'%1' (0x%2)").arg(nchar).arg(quint8(nchar),2,16,QChar('0'));
                }
                else if(type == "u8") {
                    quint8 nu8 = *reinterpret_cast<const quint8*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(nu8,0,10,QChar('0')).arg(nu8,2,16,QChar('0'));
                }
                else if(type == "u16") {
                    quint16 nu16 = *reinterpret_cast<const quint16*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(nu16,0,10,QChar('0')).arg(nu16,4,16,QChar('0'));
                }
                else if(type == "s16") {
                    qint16 ns16 = *reinterpret_cast<const qint16*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(ns16,0,10,QChar('0')).arg(ns16,4,16,QChar('0'));
                }
                else if(type == "u32") {
                    quint32 nu32 = *reinterpret_cast<const quint32*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(nu32,0,10,QChar('0')).arg(nu32,8,16,QChar('0'));
                }
                else if(type == "s32") {
                    qint32 ns32 = *reinterpret_cast<const qint32*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(ns32,0,10,QChar('0')).arg(ns32,8,16,QChar('0'));
                }
            }
        }
        //自定义数据类型
        else {
            nvalstr = "自定义类型";
        }
        return nvalstr;
    }

    /*
     * 获取值颜色
     * narridx : 数组下标
     * 返回值   : 颜色
     */
    QColor getValColor(int narridx = -1) const {
        QColor ncolor;
        if((isArray() && narridx == -1) || !isPlainDataType()) {
            ncolor = QColor(160,160,160);
        }
        else {
            ncolor = Qt::black;
        }
        return ncolor;
    }

    /*
     * 是否可以编辑
     * 返回值 : true:可编辑 false:不可编辑
     */
    bool isEditable(int narridx = -1) const {
        bool nret = true;
        if((isArray() && (narridx == -1) && !isString()) || !isPlainDataType()) {
            nret = false;
        }
        return nret;
    }

    /*
     * 获取偏移
     * nbaseoffset : 基础偏移
     * narridx     : 数组下标
     * 返回值       : 偏移
     */
    int getOffset(int nbaseoffset,int narridx = -1) const{
        int noffset = 0;
        if(narridx != -1) {
            noffset = offset + narridx * unitSize;
        }
        else {
            noffset = offset;
        }
        noffset += nbaseoffset;
        return noffset;
    }

    /*
     * 获取偏移字符串
     * nbaseoffset : 基础偏移
     * narridx     : 数组下标
     * 返回值       : 偏移字符串
     */
    QString getOffsetStr(int nbaseoffset,int narridx = -1) const{
        QString noffsetstr;
        int noffset = 0;
        noffset = getOffset(nbaseoffset,narridx);
        noffsetstr = QString::number(noffset);
        return noffsetstr;
    }

    /*
     * 计算单位尺寸
     * nstructsize : 自定义数据类型尺寸
     * 返回值       : 单位尺寸
     */
    void calcUnitSize(int nstructsize = -1) {
        //基本数据类型
        if(isPlainDataType()) {
            for(int i=0;i<PLAIN_DATA_TYPE.size();i++) {
                TDataTypeUnit ndatatypeunit = PLAIN_DATA_TYPE.at(i);
                if(type == ndatatypeunit.type) {
                    unitSize = ndatatypeunit.size;
                    break;
                }
            }
        }
        //自定义数据类型
        else {
            unitSize = nstructsize;
        }
    }

    /*
     * 获取尺寸
     * 返回值  : 尺寸
     */
    int getSize() const {
        int nsize = 0;
        nsize = unitSize * count;
        return nsize;
    }

};

//结构体
struct TLRStruct {
    QString name;     //结构体名称
    int paraStaAdd;   //数据起始地址

    QList<TLRStructMember> member;  //结构体成员
    QByteArray memData;  //数据区域

    /*
     * 添加成员
     * nlrstructmember : 成员
     */
    void appendMember(const TLRStructMember &nlrstructmember) {
        member.append(nlrstructmember);
    }

    /*
     * 转换成标准CPP结构
     */
    QString toCppString() {
        QString ncppstr;
        ncppstr.append("struct " + name + " {\r\n");
        for(const TLRStructMember &nstructmember:member) {
            QString nstructmemberstr = "    " + nstructmember.type + " " + nstructmember.name;
            if(nstructmember.count > 1) {
                nstructmemberstr.append(QString("[%1]").arg(nstructmember.count));
            }
            nstructmemberstr.append(";");
            ncppstr.append(nstructmemberstr);
            ncppstr.append("\r\n");
        }
        ncppstr.append("}");
        return ncppstr;
    }

    /*
     * 获取结构体尺寸
     * 返回值 : 结构体尺寸
     */
    int getSize() {
        int nsize = 0;
        for(int i=0;i<member.size();i++) {
            nsize += member.at(i).getSize();
        }
        return nsize;
    }

    /*
     * 分配内存
     */
    void allocMem() {
        int nsize = getSize();
        if(memData.size() != nsize) {
            memData.resize(nsize);
        }
        memset(memData.data(),0x00,size_t(memData.size()));
    }

    /*
     * 网络数据包是否匹配
     * nparastaadd : 起始地址
     * nparanum    : 数据长度
     * 返回值       ： true:匹配 false:不匹配
     */
    bool isMatch(int nparastaadd,int nparanum) {
        bool nret = false;
        if((nparastaadd == paraStaAdd) && (nparanum == getSize())) {
            nret = true;
        }
        return nret;
    }

    /*
     * 读取数据
     * pdata : 数据
     * nsize : 数据长度
     */
    void memParaCopy(const void* pdata,int nsize) {
        if(pdata) {
            if((nsize > 0) && (nsize <= memData.size())) {
                memcpy(memData.data(),pdata,size_t(nsize));
            }
        }
    }

    /*
     * 设置值
     * noffsetstr : 偏移地址
     * ntypestr   : 类型
     * nvaluestr  : 值
     */
    void setPara(const QString &noffsetstr,const QString &ntypestr,const QString &nvaluestr) {
        int noffset = noffsetstr.toInt();
        bool nconvertok = false;
        int nvalraw = 0;
        //字符模式
        if(nvaluestr.startsWith('\'') && nvaluestr.endsWith('\'')) {
            if(nvaluestr.size() == 3) {
                nvalraw = nvaluestr.toUtf8().at(1);
                nconvertok = true;
            }
        }
        //普通数字格式
        else {
            nvalraw = nvaluestr.toInt(&nconvertok);
        }
        if(nconvertok) {
            if((noffset >= 0) && (noffset < memData.size())) {
                char *pdata = memData.data() + noffset;
                if(ntypestr == "char") {
                    *pdata = char(nvalraw);
                }
                else if(ntypestr == "u8") {
                    *reinterpret_cast<quint8*>(pdata) = quint8(nvalraw);
                }
                else if(ntypestr == "u16") {
                    *reinterpret_cast<quint16*>(pdata) = quint16(nvalraw);
                }
                else if(ntypestr == "s16") {
                    *reinterpret_cast<qint16*>(pdata) = qint16(nvalraw);
                }
                else if(ntypestr == "u32") {
                    *reinterpret_cast<quint32*>(pdata) = quint32(nvalraw);
                }
                else if(ntypestr == "s32") {
                    *reinterpret_cast<qint32*>(pdata) = qint32(nvalraw);
                }
            }
        }
    }

    /*
     * 获取值
     * noffsetstr : 偏移地址
     * ntypestr   : 类型
     * nstrlen    : 字符串长度
     * 返回值      : 值
     */
    QString getPara(const QString &noffsetstr,const QString &ntypestr,int nstrlen = -1) const {
        QString nvalstr = "-Null-";
        int noffset = noffsetstr.toInt();
        if((noffset >= 0) && (noffset < memData.size())) {
            const char *pdata = memData.data() + noffset;
            //字符串类型
            if(ntypestr.startsWith("char[")) {
                if(nstrlen > 0) {
                    nvalstr = QString("\"%1\"  <%2 个项>").arg(pdata).arg(nstrlen);
                }
                else {
                    nvalstr = QString("<%2 个项>").arg(nstrlen);
                }
            }
            //普通类型
            else {
                if(ntypestr == "char") {
                    char nchar = *pdata;
                    nvalstr = QString("'%1' (0x%2)").arg(nchar).arg(quint8(nchar),2,16,QChar('0'));
                }
                else if(ntypestr == "u8") {
                    quint8 nu8 = *reinterpret_cast<const quint8*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(nu8,0,10,QChar('0')).arg(nu8,2,16,QChar('0'));
                }
                else if(ntypestr == "u16") {
                    quint16 nu16 = *reinterpret_cast<const quint16*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(nu16,0,10,QChar('0')).arg(nu16,4,16,QChar('0'));
                }
                else if(ntypestr == "s16") {
                    qint16 ns16 = *reinterpret_cast<const qint16*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(ns16,0,10,QChar('0')).arg(ns16,4,16,QChar('0'));
                }
                else if(ntypestr == "u32") {
                    quint32 nu32 = *reinterpret_cast<const quint32*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(nu32,0,10,QChar('0')).arg(nu32,8,16,QChar('0'));
                }
                else if(ntypestr == "s32") {
                    qint32 ns32 = *reinterpret_cast<const qint32*>(pdata);
                    nvalstr = QString("%1 (0x%2)").arg(ns32,0,10,QChar('0')).arg(ns32,8,16,QChar('0'));
                }
            }
        }
        return nvalstr;
    }

};

//结构体模型
class TLRStructModel
{
public:
    TLRStructModel();
    //从JSON文件中加载
    void loadFromJson(const QByteArray &njsondata);
    //查找指定类型的结构体
    TLRStruct getStruct(const QString &nlrstructname);
    //查找指定序号的结构体
    TLRStruct getStruct(int nindex);
    //获取/设置 正在通讯的结构体序号
    int getCommIndex();
    void setCommIndex(int nindex);
    //序号是否合理
    bool isIndexValid(int nindex);
    //获取模式
    QString getMode();
    //获取通讯方式
    TCommType getCommType();
    //获取设备识别字
    QString getEquidStr();

    //结构体成员
    QList<TLRStruct> m_lrstructModel;

private:
    //正在通讯的结构体序号
    int m_commIndex = -1;
    //模式
    QString m_mode = "debug";
    //通讯方式
    TCommType m_commType = TCommType::ctNet;
    //设备识别字
    QString m_equidStr;

};

#endif // TLRSTRUCTMODEL_H
